%{
#include <cstddef>
#include <cstdio>
#include <string.h>  

#include "../src/type/Type.hpp"
#include "../src/SymbTable.hpp"
#include "../src/IdentTable.hpp"
#include "../inc/Code3ad.hpp"
#include "categorie/Variable.hpp"
#include "../src/traitementTokens.hpp"
#include "../src/ConteneurCode.hpp"
#include <string>

using std::string;
extern IdentTable t;
extern SymbTable * tableCourante;
extern ConteneurCode * CCode;
extern int yyerror ( char* );
extern int yylex ();
%}
%union{
  bool bol;
    int intval;
    char * strval;
    float fval;
    c3a retour;
	int ident;
	SymbTable * ts_c;
	LexToBison ltb;
}

%type<retour>Expression;
%type<retour>MathExpr;
%type<retour>BoolExpr;
%type<retour>AtomExpr;
%type<retour>VarExpr;
%type<retour>Call;
%type<retour>Instr;
%type<retour>ProcIdent;
%type<retour>ProcDecl;
%type<retour>ProcHeader;
%type<retour>Block;
%type<retour>ValFormalArg;
%type<retour>ListIdent;
%type<retour>BaseType;




%token KW_PROGRAM
%token KW_CONST
%token KW_TYPE
%token KW_VAR
%token KW_ARRAY
%token KW_OF
%token KW_RECORD
%token KW_BEGIN
%token KW_END
%token KW_DIV
%token KW_MOD
%token KW_AND
%token KW_OR
%token KW_XOR
%token KW_NOT
%token KW_IF
%token KW_THEN
%token KW_ELSE
%token KW_WHILE
%token KW_DO
%token KW_REPEAT
%token KW_UNTIL
%token KW_FOR
%token KW_TO
%token KW_DOWNTO
%token KW_PROC
%token KW_FUNC
%token KW_NIL
%token<retour> KW_INTEGER
%token<retour> KW_REAL
%token<retour> KW_BOOLEAN
%token<retour> KW_STRING
%token<retour> KW_CHAR
%token SEP_SCOL
%token SEP_DOT
%token SEP_DOTS
%token SEP_DOTDOT
%token SEP_COMMA
%token SEP_CO
%token SEP_CF
%token SEP_PO
%token SEP_PF
%token OP_EQ
%token OP_NEQ
%token OP_LT
%token OP_LTE
%token OP_GT
%token OP_GTE
%token OP_ADD
%token OP_SUB
%token OP_MUL
%token OP_SLASH
%token OP_EXP
%token OP_PTR
%token OP_AFFECT
%token<retour> TOK_IDENT
%token<intval> TOK_INTEGER
%token<fval> TOK_REAL
%token<intval> TOK_BOOLEAN
%token<strval> TOK_STRING



%start Program 
%nonassoc OP_EQ OP_NEQ OP_GT OP_LT OP_GTE OP_LTE
%left OP_ADD OP_SUB KW_OR KW_XOR
%left OP_MUL OP_SLASH KW_AND KW_DIV KW_MOD
%right KW_NOT OP_NEG OP_POS
%left OP_EXP
%nonassoc OP_PTR
%nonassoc OP_DOT
%left SEP_CO
%nonassoc KW_IFX
%nonassoc KW_ELSE
%%
    
Program                :    ProgramHeader SEP_SCOL Block SEP_DOT
                ;
ProgramHeader            :    KW_PROGRAM TOK_IDENT {ProgHeaderFunc($2);}
                ;
Block                :   BlockDeclConst BlockDeclType BlockDeclVar BlockDeclFunc BlockCode  {}
                ;
BlockDeclConst            :    KW_CONST ListDeclConst
                 |
                 ;
ListDeclConst            :    ListDeclConst DeclConst
                 |    DeclConst
                 ;
DeclConst            :    TOK_IDENT OP_EQ Expression SEP_SCOL
                 ;
BlockDeclType            :    KW_TYPE ListDeclType
                 |
                 ;
ListDeclType            :    ListDeclType DeclType
                 |    DeclType
                 ;
DeclType            :    TOK_IDENT OP_EQ Type SEP_SCOL
                 ;
BlockDeclVar            :    KW_VAR ListDeclVar
                 |
                 ;
ListDeclVar            :    ListDeclVar DeclVar
                 |    DeclVar
                 ;
DeclVar                :    ListIdent SEP_DOTS Type SEP_SCOL
                 ;
ListIdent            :    ListIdent SEP_COMMA TOK_IDENT { $$ = $3; }
|    TOK_IDENT { $$ = $1; }
                 ;
BlockDeclFunc            :    ListDeclFunc SEP_SCOL
                 |
                 ;
ListDeclFunc            :    ListDeclFunc SEP_SCOL DeclFunc
                 |    DeclFunc
                 ;
DeclFunc            :    ProcDecl {marquerFin();}
                 |    FuncDecl {marquerFin();}
                 ;
ProcDecl            :    ProcHeader SEP_SCOL Block {ProcDeclFunc($$,$1,$3);}
                 ;
ProcHeader            :    ProcIdent
                 |    ProcIdent FormalArgs
                 ;
ProcIdent            :    KW_PROC TOK_IDENT {ProcHeaderFunc($$,$2);}
                 ;
FormalArgs            :    SEP_PO ListFormalArgs SEP_PF
                 ;
ListFormalArgs            :    ListFormalArgs SEP_SCOL FormalArg
                 |    FormalArg
                 ;
FormalArg            :    ValFormalArg 
                 |    VarFormalArg
                 ;
ValFormalArg            :    ListIdent SEP_DOTS BaseType {detectArgs($$,$1,$3);}
                 ;
VarFormalArg            :    KW_VAR ListIdent SEP_DOTS BaseType 
                 ;
FuncDecl            :    FuncHeader SEP_SCOL Block
                 ;
FuncHeader            :    FuncIdent FuncResult
                 |    FuncIdent FormalArgs FuncResult
                 ;
FuncIdent            :    KW_FUNC TOK_IDENT
                 ;
FuncResult            :    SEP_DOTS BaseType
                 ;
Type                :    UserType
                 |    BaseType
                 ;
UserType            :    EnumType
                 |    InterType
                 |    ArrayType
                 |    RecordType
                 |    PointerType
                 ;
BaseType            :    TOK_IDENT
                |   KW_INTEGER
                |    KW_REAL
                |    KW_BOOLEAN
                |    KW_CHAR
                |    KW_STRING
                ;
EnumType            :    SEP_PO ListEnumValue SEP_PF
                 ;
ListEnumValue            :    ListEnumValue SEP_COMMA TOK_IDENT
                 |    TOK_IDENT
                 ;
InterType            :    InterBase SEP_DOTDOT InterBase
                 ;
InterBase            :    NSInterBase
                 |    OP_SUB NSInterBase
                 ;
NSInterBase            :    TOK_IDENT
                 |    TOK_INTEGER
                 ;
ArrayType            :    KW_ARRAY SEP_CO ListArrayIndex SEP_CF KW_OF Type
                 ;
ListArrayIndex            :    ListArrayIndex SEP_COMMA ArrayIndex
                |    ArrayIndex
                ;
ArrayIndex            :    TOK_IDENT
                 |    InterType
                 ;
RecordType            :    KW_RECORD RecordFields KW_END
                 ;
RecordFields            :    RecordFields SEP_SCOL RecordField
                 |    RecordField
                 ;
RecordField            :    ListIdent SEP_DOTS Type
                 ;
PointerType            :    OP_PTR Type
                 ;
BlockCode            :    KW_BEGIN ListInstr KW_END
                |    KW_BEGIN ListInstr SEP_SCOL KW_END
                |    KW_BEGIN KW_END
                 ;
ListInstr            :    ListInstr SEP_SCOL Instr
                 |    Instr
                 ;
Instr                :    KW_WHILE Expression KW_DO Instr {}
                 |    KW_REPEAT ListInstr KW_UNTIL Expression {}
                 |    KW_FOR TOK_IDENT OP_AFFECT Expression ForDirection Expression KW_DO Instr {}
                 |    KW_IF Expression KW_THEN Instr %prec KW_IFX {createIf($2,$4);}
                 |    KW_IF Expression KW_THEN Instr KW_ELSE Instr{}
                 |    VarExpr OP_AFFECT Expression {VarExprOP_AFFECTExpression($$,$1,$3);}
                 |    Call
                 |    BlockCode {}
                 ;
ForDirection            :    KW_TO
                 |    KW_DOWNTO
                 ;
Expression            :    MathExpr 
                 |    CompExpr {}
                 |    BoolExpr
                 |    AtomExpr {}
                 |    VarExpr {}
                |    Call
;
MathExpr            :    Expression OP_ADD Expression {ExprOP_ADDExpr($$,$1,$3);}
                 |    Expression OP_SUB Expression {ExprOP_SUBExpr($$,$1,$3);}
                 |    Expression OP_MUL Expression {ExprOP_MULExpr($$,$1,$3);}
                 |    Expression OP_SLASH Expression {ExprOP_SLASHExpr($$,$1,$3);/* uniquement division a résultat entier*/}
                 |    Expression KW_DIV Expression

                 |    Expression KW_MOD Expression
                 |    Expression OP_EXP Expression
                 |    OP_SUB Expression %prec OP_NEG {}
                 |    OP_ADD Expression %prec OP_POS {}
                 ;
CompExpr            :    Expression OP_EQ Expression
                 |    Expression OP_NEQ Expression
                 |    Expression OP_LT Expression
                 |    Expression OP_LTE Expression
                 |    Expression OP_GT Expression
                 |    Expression OP_GTE Expression
                 ;
BoolExpr            :    Expression KW_AND Expression {KW_AND_Expr($$,$1,$3);}
                 |    Expression KW_OR Expression{KW_OR_Expr($$,$1,$3);}
                 |    Expression KW_XOR Expression{KW_XOR_Expr($$,$1,$3);}                         						
                 |    KW_NOT Expression {KW_NOT_Expr($$,$2);}
                 ;
AtomExpr            :    SEP_PO Expression SEP_PF {$$ = $2;}
                 |    TOK_INTEGER {$$.i = $1;$$.type = Type::TYPE_INTEGER;$$.calcule = true; }
                 |    TOK_REAL {$$.f = $1;$$.type = Type::TYPE_REAL;$$.calcule = true;}
                 |    TOK_BOOLEAN {$$.b = $1;$$.type = Type::TYPE_BOOL;$$.calcule = true;}
                 |    KW_NIL {/*$$.valeur = $1;*/}
                 |    TOK_STRING {$$.chet = $1;$$.type = Type::TYPE_STRING;$$.calcule = true;}
                 ;
VarExpr                :    TOK_IDENT {varExprParseIdent($$,$1);}
                |    VarExpr SEP_CO ListIndices SEP_CF
                |    VarExpr SEP_DOT TOK_IDENT %prec OP_DOT
                |    VarExpr OP_PTR
                ;
Call                 :    TOK_IDENT Parameters { CallFunc($1);}
                ;
Parameters            :    SEP_PO ListParameters SEP_PF
                |    SEP_PO SEP_PF
                ;
ListIndices            :    ListIndices SEP_COMMA Expression
                |    Expression
                ;
ListParameters            :    ListParameters SEP_COMMA Expression {CCode->ajouterInstruction(new Instruction(OPCODE_PSH, Operande($3)));}
|    Expression {CCode->ajouterInstruction(new Instruction(OPCODE_PSH, Operande($1)));}
                ;
%%



int main(int argc, char ** argv){
    tableCourante = new SymbTable();
    if (argc > 1)
        fopen(argv[1], "r");
    yyparse();
  CCode->afficher();
    /*if (argc > 1)
        fclose(yyin);*/
}

